package com.dongzili.sp_mongodb.controller;

import com.dongzili.sp_mongodb.model.User;
import com.dongzili.sp_mongodb.vo.PageVo;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Pattern;

public class BaseController<T> {

    @Getter
    private Class<T> classType;

    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private MongoRepository mongoRepository;

    @SuppressWarnings("unchecked")
    public BaseController() {
        Type superClass = getClass().getGenericSuperclass();
        if (superClass instanceof Class) {
            throw new RuntimeException("Missing type parameter.");
        }
        ParameterizedType parameterizedType = (ParameterizedType) superClass;
        this.classType = (Class<T>) parameterizedType.getActualTypeArguments()[0];
    }

    @PostMapping("/insert")
    public Object create(@RequestBody T entity) {
        return mongoTemplate.save(entity);
    }

    @GetMapping("/findById/{id}")
    public Optional<T> findById(@PathVariable String id) {
        return Optional.ofNullable(mongoTemplate.findById(id, classType));
    }
    @GetMapping
    public List<T> getAllUsers() {
        return mongoRepository.findAll();
    }

    @PostMapping("/findPageUserAll")
    public List<T> findPageUserAll(@RequestBody PageVo<T> pageVo) {
//        return userService.findPageUserAll(page.getPageNum(), page.getPageSize(), page.getData());
        Pageable pageable = PageRequest.of(pageVo.getPageNum(), pageVo.getPageSize());

        Example<T> example = Example.of(pageVo.getData());//查询条件
        Page page = mongoRepository.findAll(example, pageable);
        return page.getContent();
    }

    @GetMapping("/deleteById/{id}")
    public DeleteResult deleteById(@PathVariable String id, Class<T> clazz) {
        Query query = new Query(Criteria.where("_id").is(id));
        return mongoTemplate.remove(query, clazz);
    }

    @PostMapping("/updateById/{id}")
    public Optional<T> updateById(@PathVariable String id,@RequestBody T entity) {
        if (mongoRepository.existsById(id)) {
            Query query = new Query(Criteria.where("_id").is(id));
            Update update = new Update();
            // 检查entity对象中所有字段，如果不为空则更新
            Field[] fields = classType.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                try {
                    Object value = field.get(entity);
                    if (value != null) {
                        update.set(field.getName(), value);
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
            UpdateResult result = mongoTemplate.updateFirst(query, update, User.class);
            System.out.println(result);
            return mongoRepository.findById(id);
        }
        return null;
    }

    @PostMapping("/dynamicQuery")
    public List<T> dynamicQuery(@RequestBody List<Map<String, Map<String, Map<String, Object>>>> queryList) {
        // 创建一个 Criteria 对象，用于构建查询条件
        Criteria criteria = new Criteria();
        // 遍历条件列表
        for (Map<String, Map<String, Map<String, Object>>> condition : queryList) {
            // 创建一个 Criteria 对象，用于存储子条件
            Criteria subCriteria = new Criteria();

            // 遍历每个操作符下的条件
            for (Map.Entry<String, Map<String, Map<String, Object>>> entry : condition.entrySet()) {
                String operator = entry.getKey(); // 获取操作符 ("and" 或 "or")
                Map<String, Map<String, Object>> subCondition = entry.getValue(); // 获取对应的条件

                // 遍历每个条件
                for (Map.Entry<String, Map<String, Object>> subEntry : subCondition.entrySet()) {
                    String key = subEntry.getKey(); // 获取条件字段名
                    Map<String, Object> value = subEntry.getValue(); // 获取条件值

                    System.out.println(operator);
                    // 根据操作符应用相应的条件
                    switch (operator) {
                        case "and":
                            subCriteria = applyCriteria(subCriteria, key, value); // 应用 "and" 条件
//                            Query dynamicQuery1 = new Query(subCriteria);
                            break;
                        case "or":
                            // 创建新的 Criteria 对象来处理 "or" 条件
//                            Criteria orCriteria = new Criteria();
                            Criteria orCriteria = applyCriteria(new Criteria(), key, value); // 应用 "or" 条件
                            subCriteria.orOperator(orCriteria); // 将 "or" 条件添加到子条件中
//                            Query dynamicQuery2 = new Query(orCriteria);
                            break;
                        default:
                            // 可以添加日志或异常处理，说明未处理的条件
                            break;
                    }
                }
            }
            // 将子条件添加到主条件中，使用 "and" 连接
            criteria.andOperator(subCriteria);
        }

        // 构建查询对象，并执行查询
        Query dynamicQuery = new Query(criteria);
        return mongoTemplate.find(dynamicQuery, getClassType());
    }

    // 根据条件类型应用相应的查询条件
    private Criteria applyCriteria(Criteria criteria, String fieldName, Map<String, Object> map) {

        Criteria finalCriteria = criteria.and(fieldName);
        map.forEach((key, value) ->{
            System.out.println(fieldName+":> "+key + ":" + value);
            switch (key) {
                case "eq":
                    finalCriteria.is(value); // 等于
                    break;
                case "ne":
                    finalCriteria.ne(value); // 不等于
                    break;
                case "gt":
                    finalCriteria.gt(value); // 大于
                    break;
                case "gte":
                    finalCriteria.gte(value); // 大于等于
                    break;
                case "lt":
                    finalCriteria.lt(value); // 小于
                    break;
                case "lte":
                    finalCriteria.lte(value); // 小于等于
                    break;
                case "in":
                    finalCriteria.in((List<?>) value); // 包含于
                    break;
                case "nin":
                    finalCriteria.nin((List<?>) value); // 不包含于
                    break;
                case "exists":
                    finalCriteria.exists((Boolean) value); // 存在
                    break;
                case "regex":
                    finalCriteria.regex(Pattern.compile(value.toString())); // 正则表达式匹配
                    break;
                case "like":
                    finalCriteria.regex(Pattern.compile(value.toString(), Pattern.CASE_INSENSITIVE)); // 模糊匹配
                    break;
                case "between":
                    List<?> betweenValues = (List<?>) value;
                    if (betweenValues.size() == 2) {
                        finalCriteria.gte(betweenValues.get(0)).lte(betweenValues.get(1)); // 范围查询
                    }
                    break;
                case "all":
                    finalCriteria.all((List<?>) value); // 包含所有指定元素
                    break;
                case "size":
                    finalCriteria.size((Integer) value); // 数组大小
                    break;
                case "elemMatch":
                    if (value instanceof Map) {
                        Criteria elemMatchCriteria = new Criteria();
                        ((Map<?, ?>) value).forEach((k, v) -> elemMatchCriteria.and(k.toString()).is(v)); // 元素匹配
                        finalCriteria.elemMatch(elemMatchCriteria);
                    }
                    break;
                // 可以继续添加更多的比较符...
                default:
                    // 可以添加日志或异常处理，说明未处理的条件
                    break;
            }
        });
        Query dynamicQuery = new Query(finalCriteria);
        return finalCriteria;
    }



    @PostMapping("/dynamicQuery1")
    public List<T> dynamicQuery(@RequestBody Map<String, List<Map<String, Map<String, Object>>>> request) {

//        Criteria criteria = new Criteria();

//        criteria.orOperator(new Criteria().and("age").gt(27).and("username").regex(Pattern.compile("user8", Pattern.CASE_INSENSITIVE)),new Criteria().and("email").is("123456@163.com"));
//        Query query = new Query(criteria);
//        return mongoTemplate.find(query, classType);

        Criteria criteria = new Criteria();

        List<Map<String, Map<String, Object>>> conditions = request.get("conditions");

        for (Map<String, Map<String, Object>> condition : conditions) {


            for (Map.Entry<String, Map<String, Object>> entry : condition.entrySet()) {
                String operator = entry.getKey(); // 获取操作符 ("and" 或 "or")
                Map<String, Object> subCondition = entry.getValue(); // 获取对应的条件

                List<Criteria> subCriteriaList = new ArrayList<>();
                // 遍历每个条件
                for (Map.Entry<String, Object> subEntry : subCondition.entrySet()) {
                    String fieldName = subEntry.getKey(); // 获取条件字段名
                    Map<String, Object> fieldValue = (Map<String, Object>) subEntry.getValue(); // 获取条件值

                    Criteria subCriteria = new Criteria();
                    // 根据操作符应用相应的条件
                    for (Map.Entry<String, Object> valueEntry : fieldValue.entrySet()) {
                        String key = valueEntry.getKey(); // 获取条件操作符
                        Object value = valueEntry.getValue(); // 获取条件值

                        switch (key) {
                            case "eq":
                                subCriteria.and(fieldName).is(value); // 等于
                                break;
                            case "ne":
                                subCriteria.and(fieldName).ne(value); // 不等于
                                break;
                            case "gt":
                                subCriteria.and(fieldName).gt(value); // 大于
                                break;

                            case "gte":
                                subCriteria.and(fieldName).gte(value); // 大于等于
                                break;
                            case "lt":
                                subCriteria.and(fieldName).lt(value); // 小于
                                break;
                            case "lte":
                                subCriteria.and(fieldName).lte(value); // 小于等于
                                break;
                            case "in":
                                subCriteria.and(fieldName).in((List<?>) value); // 包含于
                                break;
                            case "nin":
                                subCriteria.and(fieldName).nin((List<?>) value); // 不包含于
                                break;
                            case "exists":
                                subCriteria.and(fieldName).exists((Boolean) value); // 存在
                                break;
                            case "regex":
                                subCriteria.and(fieldName).regex(Pattern.compile(value.toString())); // 正则表达式匹配
                                break;
                            case "like":
                                subCriteria.and(fieldName).regex(Pattern.compile(value.toString(), Pattern.CASE_INSENSITIVE)); // 模糊匹配
                                break;
                            case "between":
                                List<?> betweenValues = (List<?>) value;
                                if (betweenValues.size() == 2) {
                                    subCriteria.and(fieldName).gte(betweenValues.get(0)).lte(betweenValues.get(1)); // 范围查询
                                }
                                break;
                            case "all":
                                subCriteria.and(fieldName).all((List<?>) value); // 包含所有指定元素
                                break;
                            case "size":
                                subCriteria.and(fieldName).size((Integer) value); // 数组大小
                                break;
                            case "elemMatch":
                                if (value instanceof Map) {
                                    Criteria elemMatchCriteria = new Criteria();
                                    ((Map<?, ?>) value).forEach((k, v) -> elemMatchCriteria.and(k.toString()).is(v)); // 元素匹配
                                    subCriteria.and(fieldName).elemMatch(elemMatchCriteria);
                                }
                                break;

                            // 可以继续添加更多的比较符...
                            default:
                                // 可以添加日志或异常处理，说明未处理的条件
                                break;
                        }
                    }
                    subCriteriaList.add(subCriteria);
                }

                // 将子条件添加到主条件中，使用 "and" 或 "or" 连接
                if (operator.equals("and")) {
                    criteria.andOperator(subCriteriaList);
                } else if (operator.equals("or")) {
                    criteria.orOperator(subCriteriaList);
                }
            }
        }

        // 构建查询对象，并执行查询
        Query query = new Query(criteria);
        return mongoTemplate.find(query, classType);


    }
}
